package prometheus

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"github.com/linclaus/stock/pkg/common/util"

	"github.com/linclaus/stock/pkg/model"
	"github.com/prometheus/prometheus/pkg/rulefmt"
	yaml "gopkg.in/yaml.v2"
)

func DeleteRuleAndWriteFile(s model.Strategy) error {
	rule := rulefmt.Rule{
		Alert: s.StrategyId,
	}
	return deleteRulesFromGroups(s.Code+RULE_FILE_SUFFIX, rule)
}

func GenerateRuleAndWriteFile(s model.Strategy) error {
	rule := rulefmt.Rule{
		Alert:       s.StrategyId,
		Expr:        util.GeneratePrometheusExpression(s),
		Annotations: util.GeneratePrometheusAnnotations(s),
		Labels:      util.GeneratePrometheusLabels(s),
	}
	return addRulesToGroups(s.Code+RULE_FILE_SUFFIX, rule)
}

func deleteRulesFromGroups(fileName string, rule rulefmt.Rule) error {
	rgs, err := rulefmt.ParseFile(RULE_FILE_PATH + fileName)
	if err != nil {
		fmt.Printf("file doesn't exist, %s will be created\n", fileName)
		return err[0]
	}

	rgs.Groups[0].Rules = deleteRule(rgs.Groups[0].Rules, rule)
	return writeRuleToFile(*rgs, fileName)
}

func addRulesToGroups(fileName string, rule rulefmt.Rule) error {
	rgs, err := rulefmt.ParseFile(RULE_FILE_PATH + fileName)
	if err != nil {
		fmt.Printf("file doesn't exist, %s will be created\n", fileName)
		rgs = &rulefmt.RuleGroups{
			Groups: []rulefmt.RuleGroup{
				rulefmt.RuleGroup{
					Name:  fileName,
					Rules: []rulefmt.Rule{},
				},
			},
		}
	}

	rgs.Groups[0].Rules = mergeOrAddRule(rgs.Groups[0].Rules, rule)
	return writeRuleToFile(*rgs, fileName)
}

func mergeOrAddRule(rules []rulefmt.Rule, rule rulefmt.Rule) []rulefmt.Rule {
	for _, r := range rules {
		if r.Alert == rule.Alert {
			return rules
		}
	}
	return append(rules, rule)
}

func deleteRule(rules []rulefmt.Rule, rule rulefmt.Rule) []rulefmt.Rule {
	results := []rulefmt.Rule{}
	for _, r := range rules {
		if r.Alert == rule.Alert {
			continue
		}
		results = append(results, r)
	}
	return results
}

// WriteRuleGroups
func writeRuleToFile(rgs rulefmt.RuleGroups, fileName string) error {
	res, _ := yaml.Marshal(rgs)
	file, err := os.OpenFile(RULE_FILE_PATH+fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	defer file.Close()
	if err != nil {
		fmt.Println("文件打开失败", err)
		return err
	}
	write := bufio.NewWriter(file)
	write.WriteString(string(res))
	write.Flush()
	reloadPrometheus()
	return nil
}

func reloadPrometheus() {
	http.Post(PROMETHEUS_HOST+"/-/reload", "application/json", nil)
}

func QueryPrometheusForCodes(queryString string) []string {
	fmt.Println(queryString)
	resp, err := http.Get(fmt.Sprintf(PROMETHEUS_HOST+"/api/v1/query?query=%s", queryString))
	var codes []string
	if err == nil {
		defer resp.Body.Close()
		if resp.StatusCode == 200 {
			body, err := ioutil.ReadAll(resp.Body)

			if err != nil {
				log.Println(err)
				return codes
			}
			var r PrometheusVectorResponse
			json.Unmarshal(body, &r)
			for _, rst := range r.Data.Result {
				codes = append(codes, rst.Metric["code"].(string))
			}
		}
	}
	fmt.Println(codes)
	return codes
}
